<!DOCTYPE html>
<!-- saved from url=(0102)https://www.codeproject.com/Articles/624495/Custom-Controls-in-Win-API-Standard-Messages?display=Print -->
<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
	<title>Custom Controls in Win32 API: Standard Messages - CodeProject</title> 
	<link type="text/css" rel="stylesheet" href="./Custom Controls in Win32 API_ Standard Messages - CodeProject_files/Main.min.css">

	
<meta http-equiv="content-language" content="en-US">

<meta name="Description" content="Make your control answer to the questions system or application may ask.; Author: Martin Mitáš; Updated: 17 Mar 2014; Section: Windows API; Chapter: Platforms, Frameworks &amp; Libraries; Updated: 17 Mar 2014">
<meta name="Keywords" content="C, Windows, Win32, Win64, Dev, VS2010, custom-controls,Windows API,Platforms, Frameworks &amp; Libraries,Free source code, tutorials">
<meta name="Author" content="Martin Mitáš">
<meta name="Rating" content="General">
<meta name="Revisit-After" content="1 days">
<meta name="application-name" content="CodeProject">
<meta name="google-translate-customization" content="d908bb7ce7aff658-4c2f3a504525c916-g629383f736781a8a-13">

<link rel="dns-prefetch" href="https://ajax.googleapis.com/"> 
<link rel="canonical" href="https://www.codeproject.com/Articles/624495/%2fArticles%2f624495%2fCustom-Controls-in-Win-API-Standard-Messages">
<link rel="alternate" type="application/rss+xml" title="CodeProject Latest articles - All Topics" href="https://www.codeproject.com/WebServices/ArticleRSS.aspx?cat=1">
<link rel="alternate" type="application/rss+xml" title="CodeProject Latest articles - Artificial Intelligence" href="https://www.codeproject.com/WebServices/ArticleRSS.aspx?cat=31">
<link rel="alternate" type="application/rss+xml" title="CodeProject Lounge Postings" href="https://www.codeproject.com/webservices/LoungeRSS.aspx">
<meta name="robots" content="index, follow">
<link rel="search" type="application/opensearchdescription+xml" title="CodeProject" href="https://www.codeproject.com/info/OpenSearch.xml">
<meta name="viewport" content="width=device-width, initial-scale=1.0">

<link rel="apple-touch-icon" sizes="144x144" href="https://www.codeproject.com/favicon/apple-touch-icon.png"> 
<link rel="icon" type="image/png" sizes="32x32" href="https://www.codeproject.com/favicon/favicon-32x32.png"> 
<link rel="icon" type="image/png" sizes="16x16" href="https://www.codeproject.com/favicon/favicon-16x16.png"> 
<link rel="manifest" href="https://www.codeproject.com/favicon/manifest.json"> 
<link rel="mask-icon" href="https://www.codeproject.com/favicon/safari-pinned-tab.svg" color="#ff9900">
	
<script type="application/ld+json">
{
  "@context": "http://schema.org",
  "@type": "TechArticle",
  "headline": "Custom Controls in Win32 API: Standard Messages",
  "url": "https://www.codeproject.com/Articles/624495/Custom-Controls-in-Win-API-Standard-Messages",
  "discussionUrl": "https://www.codeproject.com/Articles/624495/Custom-Controls-in-Win-API-Standard-Messages",
  "isFamilyFriendly": "true",
  "image": "https://codeproject.global.ssl.fastly.net/App_Themes/CodeProject/Img/Article100.png",
  "keywords": "C, Windows, Win32, Win64, VS2010, custom-controls",
  "commentCount": "5",
  "editor" : {
    "@type" : "Person",
    "name" : "Martin Mitáš",
    "url" : "https://www.codeproject.com/script/Membership/View.aspx?mid=5807385"
  },
  "license": "http://www.codeproject.com/info/cpol10.aspx",
  "publisher" : {
    "@type" : "Organization",
    "name" : "CodeProject"
  }
  "description": "Make your control answer to the questions system or application may ask.",
  "upvoteCount": "34",
  "articleSection": "Windows API",
  "author" : [{
      "@type" : "Person",
      "name" : "Martin Mitáš",
      "url" : "https://www.codeproject.com/script/Membership/View.aspx?mid=5807385"
    }],
  "datePublished": "2013-07-30",
  "dateCreated": "2013-07-30",
  "dateModified": "2014-03-17",
  "aggregateRating" : {
    "@type" : "aggregateRating",
    "ratingValue" : 4.94,
    "ratingCount" : 34,
    "bestRating" : 5,
    "worstRating" : 1
  },
}
</script>
<script type="application/ld+json">
{
  "@context": "http://schema.org",
  "@type": "BreadcrumbList",
  "itemListElement": [{
    "@type": "ListItem",
    "position": 1,
    "item" : {
      "@id" : "/Chapters/8/Platforms-Frameworks-Libraries.aspx",
      "name" : "Platforms, Frameworks & Libraries"
    }
  },{
    "@type": "ListItem",
    "position": 2,
    "item" : {
      "@id" : "/KB/vista/",
      "name" : "Windows API"
    }
  }]
}
</script>
	<!--<base target="_top">--><base href="." target="_top">
	<script type="text/javascript" src="./Custom Controls in Win32 API_ Standard Messages - CodeProject_files/jquery.2.2.4.min.js.下载"></script><script type="text/javascript">//<![CDATA[
if (typeof jQuery == 'undefined') {
    document.write(unescape("%3Cscript src='%2fscript%2fJS%2fjquery-2.2.4.min.js' type='text/javascript' %3E%3C/script%3E"));
}//]]></script><script src="./Custom Controls in Win32 API_ Standard Messages - CodeProject_files/jquery-2.2.4.min.js.下载" type="text/javascript"></script>
<script type="text/javascript">//<![CDATA[
function defrm () { /* thanks twitter */ document.write = ''; window.top.location = window.self.location;  setTimeout(function() { document.body.innerHTML = ''; }, 0);  window.self.onload = function(evt) { document.body.innerHTML = ''; }; }if (window.top !== window.self) {  try {  if (window.top.location.host) { /* will throw */ } else { defrm(); /* chrome */ }  } catch (ex) { defrm(); /* everyone else */ } }if (typeof(DemoUrl)!='undefined')   document.write(unescape('%3Cme')+'ta http'+'-equiv="re'+'fresh"                  con'+'tent="1;url='+DemoUrl+unescape('"%3CE'));

//]]>
</script>

	




<script type="text/javascript">
	var _gaq = _gaq || [];
	_gaq.push(['_setAccount', 'UA-1735123-1']);
	_gaq.push(['_trackPageview']);
	_gaq.push(['_setDomainName', 'www.codeproject.com']);
	_gaq.push(['_setSessionTimeout', '1200']); 

	(function () {
		var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
		ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
		(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(ga);
	})(); 
</script><script type="text/javascript" async="" src="./Custom Controls in Win32 API_ Standard Messages - CodeProject_files/ga.js.下载"></script>


</head>	

<body class="chrome chrome67 touch">

<a class="access-link" href="https://www.codeproject.com/Articles/624495/Custom-Controls-in-Win-API-Standard-Messages?display=Print#Main"><img alt="Click here to Skip to main content" src="./Custom Controls in Win32 API_ Standard Messages - CodeProject_files/t.gif"></a>





<div class="page-background">

	
	

	

	
    <div id="ctl00_STM" class="site-top-menu fluid">
        <div class="main-content">
            
        </div>
    </div>

	
    <div id="ctl00_SH" class="site-header fluid">
        <div class="main-content">
            <div class="logo"><a href="https://www.codeproject.com/"><img id="ctl00_Logo" tabindex="1" title="CodeProject" src="./Custom Controls in Win32 API_ Standard Messages - CodeProject_files/logo250x135.gif" alt="Home" style="height:135px;width:250px;border-width:0px;"></a></div>
            <div class="promo"></div>
        </div>
    </div>

	<a href="https://www.codeproject.com/Articles/624495/Custom-Controls-in-Win-API-Standard-Messages?display=Print#Main"><img alt="Click here to Skip to main content" class="access-link" src="./Custom Controls in Win32 API_ Standard Messages - CodeProject_files/t.gif"></a>

	
			
	

	<div id="A" class="container-content-wrap fluid print"> 
	<div class="container-content">


		<div class="clearfix">
			<div class="container-breadcrumb float-left ">
				<div><a href="https://www.codeproject.com/script/Content/SiteMap.aspx">Articles</a> » <a href="https://www.codeproject.com/Chapters/8/Platforms-Frameworks-Libraries.aspx">Platforms, Frameworks &amp; Libraries</a> » <a href="https://www.codeproject.com/KB/vista/">Windows API</a> » <a href="https://www.codeproject.com/KB/vista/#General">General</a></div>
			</div>

            <div class="float-left">
				
			</div>

			<div class="edit-links float-right">
				
			</div>

			<div class="article-nav float-right">
                
				
			</div>
		</div>

		<table class="extended container-article-parts" cellpadding="0" cellspacing="0">
        <tbody><tr valign="top">
		<td width="117px" class="article-wing-left">

			

		</td>
		<td>
			
			<div id="AT" class="container-article  fluid tight"> 

				<div class="article">

					<form name="aspnetForm" method="post" action="https://www.codeproject.com/Articles/624495/Custom-Controls-in-Win-API-Standard-Messages?display=Print" id="aspnetForm" style="margin:0;padding:0">
<div>
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="C2NoD4WAe4priz1S+hjPhUuKmk68WdBb/Chn2qi+tfUjOVgvrSiz976MU8pztrqQwNik724OefmjlnZ1WEnwPjLCRfl3ZwG8DrqshFcuY+L39DWdP/JqYp75vcZW7Vg+OLR1ywkBM2ehz8IrcZraIhXoj5BWABqT755KLZYr1/A5m4LjADq6JTR7uUtSlrDzVgCEJP3OOd/o5OMOnXJMeK14hpvJYDhGBPJ+CDjJr55HDfEaR9JcO1oj4vEg9/9EKP1hrjigvF1TWWXxivJ7oCO5xHIC5vERz5cMFPH3U686+G9hHyq5hSAVGjmd5fF3r7aah2gk4EkV0xpnhBipaqg8vDRpx5bHIev3IquDTLJi8vwwOIiyfFrrO4j8qV74ZM1eHGwW4EGSbxf7ir9V5pVLTNIHBQqfX6AixXUv34U50PIV5nhjftMM82/qQsRI/XwiqPaB/oYYTSDCt5NvKjq8VZumUqx7HDABa1UEZKVDTHY1UnESAbDC7R4lZLdLGKW+rwSzNn1G2B0quQxJpUwrRe8MlFcDueLG/iucnRaLyMlUWZa9IxoUrdoiH/RtJZKL89m3xSBzZ/VsjTacbuLG/x4WJRoxCOHzDLCL88PJ2ii4piBisgyPGOnSwVeZkUvD0jPsnRyw/qyNT5e+Gq9Z2zCzAN5oBKqT5kh5Dwwy2LNggO7avfCHQrRk2CgGdleQ2jYfzlvmELVzBEYokumxkaysXkVyISAT/BvDFsxQOzcd96mVzWpOn8tIpqvaNfgSx5MOj0JVE3gyVPjQXBAjix0jTtS2ooz/B0Nb1M7fUnGmjWVmdD9NnRtff9TQ6PdiMtJ5NpPPtPVGjifASJ561c8BaHJny4dKsw2rspN7LsGuwoqtjfqyzrtpNYC7NhQmGGRB+HTLrrqFnEnRddCoexzWkyVoJPVqXCABQnr/+SnSarRtvUbdcNQ2tk6+Yj4hUoCsb8ZC8I/EzwrCG8kuqbkIGKOHl2W7AJdTDhKuhuaKPmbhh7VI2eEjOkVEz8ietQDXI9qqksDwnDtsPE+ctH4UuWqipJQt2l9R/W+00HI1+jsrb9UmnVvxs3gOOmo/l4MWjWUQpKf1LefeDza36kCzLJe0W79SmZBlKGYp8z7WKib2WgjChK9o0XmxmbKkDHjeHtZv2LJgCHSEpMjcuw5Uj7m4NcxwVABPxoO1AOjcM55OR6Gu+pwHgGwwxgxDV0SJ3471pHhQy6iow6FROVsy+LvDhSMLkY7uQPoSwzbltCYQJtzzNxihGU9H+2dPeMegvIKkorVKWRiVcii2nzXixEluKt9rQfwisuBzLVrdWbHOPtHf4H/t0AOWXvBr9+IP4Wd2VeQolTQ6SvvH7nuCtjei2ZAwpReE5gypo6KOF55YvVMsF1PzbpFizM/70JYylOprNp5xMouyLa4E5Q+ZmBjoFTgk6/vO7kka7Kza2iR7o1lQHlLe5mCvrSfIAJP8CS4lVEj2+neNjicpyi84Jap8tqQSCEf8OUMoYJTG4Q+gBXUb2VMjQaePb0cc0y0zcFLWjx2FfRg2wSp0L1zFxN54BIx607APfsElEfuOeQOI19fXD4BomlWIECP0N5tqNxHVwGrLK6JWz7ba10o0ae4pejhBQwfxoEDvJhe+TRGPFpaOdYXBBkdOftSz4wiP6xqW59qIsq4FE7T1NrvUXOSWVZXBf1aS+7y9G0YJfFEiMRkEBmC30gts1nmVNNY42W2eE85uWC8+fD/KwsiIWDxjCevuaGcLOKYJkBd2+3lMo9f3ej/gT1XrwX4aSLyu0xyIvHfQ8uRhoiCgAJ6nqDbo4QK/jbATS3ZVmO2rZXqvbNcCwLIaiv2WuA9KSHm9mROXKjWGBTvg7yooj6+e+oyn4M77s/S81H9R5KqO95vfLUYPaRRSuoVsobq9hfLGVf9ZEo0j/VGEaBdaq7ZFPyG5ZAEl2/aSUCwV4kP+HelRr7a/L+NNbABpx3OcSXrjnCU2btN4tAQ7eZWQifOpIgxuX/yy0jZWIHaJxW3W6vejbldwQKrM/s8bwPxXshSl8G6nh46rdlsA1jglOZrEHPuS8/tuDSf3Wtoiu8h8CzvcIKod+wvr0UVGHAZaHK8k61AAj0IAIIXrsNEoSToznpBFlVabtdCtMut+MGlEYA2WPDtk7pJqXl1vGlwsi99ifHOurVcQI0qwadFnTVLpyVztQ+amRNHejqZVWrB6gO8uvIiUiK/IiiRiUUSaNYVeKVuP09AQAX4dpvRlToGR/fStllstkzqMbrpa2saDcLOjI8j2nekPJ9YFl7ISHetjCBlltapt7o1H4+dst7n+CTuLMRVGEhOb6/ERIt3C3pLT3FbuDqkb1ZwTBQ+dJLPoDoYQbsePBpaE0/ISTcIdiXuVVM8zZ1objlDzcHcJi9TUaMXT0qptSdHaB9ixw8E3AJtdq4mCJTxSJCV27NLGn62FBFYkDmcB2zV3amUx">
</div>

<div>

	<input type="hidden" name="__VIEWSTATEGENERATOR" id="__VIEWSTATEGENERATOR" value="10C1FD69">
</div>

					
					 
					<div class="header">
					    <a name="Main"></a>

					    
					    <a name="_articleTop" id="_articleTop"></a>
					    <div class="title">
					        <h1 id="ctl00_ArticleTitle">Custom Controls in Win32 API: Standard Messages</h1>
					    </div>

                        <div style="height:34px">
					        
					        <div class="entry float-left">

                                <img src="./Custom Controls in Win32 API_ Standard Messages - CodeProject_files/58de2d085c17e28b8951315245dd408c.jpeg" id="ctl00_avatar" class="float-left avatar">

                                <div class="float-left">
                                    <div>
						                <span class="author"><a href="https://www.codeproject.com/script/Membership/View.aspx?mid=5807385" rel="author">Martin Mitáš</a></span>, 
						                <span class="date" title="Date last updated">
							            18 Mar 2014</span>
			                        </div>

                                    
						            
    						        	

                                </div>

    	                        	
                                <div class="float-left" style="margin: 25px 0 0 10px;">
	                                
	                            </div>
                         	    	
    
					        </div>

                            

						    <div id="ctl00_AdManagerWrap" class="float-right align-center">
                                
						    </div>

                        </div>

                        <div id="ctl00_description" class="summary">Make your control answer to the questions system or application may ask.</div><span id="ctl00_thumbnailUrl" class="date" content="https://codeproject.global.ssl.fastly.net/script/Articles/Images/article100x80.png"></span>			

                    </div>
                    
					
					

					

					
					
					

						
					

					

						
						<div id="contentdiv" class="text">
						



<ul class="download">
	<li><a href="https://www.codeproject.com/KB/vista/624495/button.zip">Download custom control demo - 67.6 KB</a></li></ul>

<h2>Articles in this series</h2>

<ul>
	<li><a href="http://www.codeproject.com/Articles/559385/Custom-Controls-in-Win32-API-The-Basics">Custom Controls in Win32 API: The Basics</a></li>	<li><a href="http://www.codeproject.com/Articles/617212/Custom-Controls-in-Win32-API-The-Painting">Custom Controls in Win32 API: The Painting</a></li>	<li><a href="http://www.codeproject.com/Articles/620045/Custom-Controls-in-Win32-API-Visual-Styles">Custom Controls in Win32 API: Visual Styles</a></li>	<li>Custom Controls in Win32 API: Standard Messages</li>	<li><a href="http://www.codeproject.com/Articles/646482/Custom-Controls-in-Win-API-Control-Customization">Custom Controls in Win32 API: Control Customization</a></li>	<li><a href="http://www.codeproject.com/Articles/744603/Custom-Controls-in-Win-API-Encapsulation-of-Cust">Custom Controls in Win32 API: Encapsulation of Customized Controls</a></li>	<li><a href="http://www.codeproject.com/Articles/1042516/Custom-Controls-in-Win-API-Scrolling">Custom Controls in Win32 API: Scrolling</a></li></ul>

<h2>Introduction</h2>

<p>In previous articles we engaged in painting the controls. Today, we are going to pay some attention to handling many messages which mediate interaction between the control, its dialog or other parent window, and also between the control and the operating system itself.</p>

<p>Note that, as all the articles in this series, this is not a reference documentation. This article is not meant as a replacement of MSDN. It is meant as complementary to it. MSDN often describes what the message is about, how its parameters are passed to it via <code>WPARAM</code> and <code>LPARAM</code> and I cannot see any sense in repeating it here. Instead, this article provides just an overview of messages controls often need to implement, with some hints how to do that from point of view of the control, not application attempting to just send the message to a control.</p>

<h2>Unicode and ANSI Strings</h2>

<p>Before we start talking about the number of messages, lets take a little talk on strings and how standard controls handle the Unicode vs. ANSI duality of the Win32 API, as that obviously has some impact how the custom controls should handle string parameters too.</p>

<p><strong>Note:</strong> <em>Unicode</em> in context of Win32 API means UTF-16 encoding in little-endian byte order. (On Windows 2000, it was only UCS-2, i.e. subset of UTF-16 without the support for surrogate pairs.) <em>Windows ANSI</em>, or just <em>ANSI</em> in Win32 API context, is a misnomer meaning a byte-oriented encoding determined by current <em>code page</em>. Unlike in Unicode, the same sequence of bytes has different meaning in different code pages and, often, may be invalid. In general, all new code should prefer to use Unicode, at least internally.</p>

<p>Most control-specific messages which take string as a parameter (or a pointer to structure having string as a member) are actually two distinct messages. The Unicode-flavored message has a suffix <code>W</code>, the ANSI-flavored one has a suffix <code>A</code>. The preprocessor macro <code>UNICODE</code> then in public header controls which one is used when application source uses the message name without either of the suffices.</p>

<p>However that is mainly true about control-specific messages. You can find many examples of this approach in <em>commctrl.h</em> for messages responsible to insert or set items of controls like list view or tree view.</p>

<p>The standard messages, in particular <code>WM_NCCREATE</code>, <code>WM_CREATE</code>, <code>WM_SETTEXT</code> and <code>WM_GETTEXT</code>, work a bit differently. There are no Unicode/ANSI flavors of these messages. Instead the system remembers whether the window class was registered with <code>RegisterClassW()</code> or <code>RegisterClassA()</code> (or their <code>RegisterClassEx()</code> counterparts). Depending on this, we call the resulted <code>HWND</code>s to be <em>Unicode windows</em> or <em>ANSI windows</em>.</p>

<p>All the relevant functions like <code>CreateWindow()</code>, <code>SetWindowText()</code> or <code>GetWindowText()</code> have the Unicode or ANSI flavor (again, suffix <code>W</code> or <code>A</code> respectively in the function name). Whenever the function is called, it makes automatically the required conversion to pass the string to the window procedure in the corresponding form.</p>

<p>As globalization advances, internationalization and localization are natural demands on any modern software. Hence Unicode rules more and more this world and the standard controls internally always work in Unicode (at least since Windows 2000). I recommend following this rule of thumb in your controls, unless you have very strong reason to do otherwise.</p>

<p>That, in general, means to follow these steps:</p>

<ul>
	<li>Register your control with Unicode flavor of <code>RegisterClass()</code>.</li>	<li>Interpret strings in the standard messages as Unicode.</li>	<li>Hold strings in control's structures in Unicode.</li>	<li>When implementing new control-specific message, implement it either for Unicode, or implement two distinct messages. The code below demonstrates this.</li></ul>

<p><strong>Note:</strong> The first three points of the list can be achieved by using explicitly the <code>W</code>-flavors of the functions like <code>RegisterClassW()</code> etc., or with using the Unicode resolution macros (the name without any suffix) and building the project as Unicode one by using appropriate compiler options. In Visual Studio, this can be configured in project properties, gcc compiler has the option <em>-municode</em> for this purpose.</p>

<pre lang="C"><span class="code-comment">/*</span><span class="code-comment"> custom.h
 * (public control interface) */</span>

...

<span class="code-preprocessor">#define XXM_SOMESTRINGMESSAGEW     (WM_USER+100)
</span><span class="code-preprocessor">#define XXM_SOMESTRINGMESSAGEA     (WM_USER+101)
</span><span class="code-preprocessor">#ifdef UNICODE
</span>    <span class="code-preprocessor">#define XXM_SOMESTRINGMESSAGE     XXM_SOMESTRINGMESSAGEW
</span><span class="code-preprocessor">#else
</span>    <span class="code-preprocessor">#define XXM_SOMESTRINGMESSAGE     XXM_SOMESTRINGMESSAGEA
</span><span class="code-preprocessor">#endif
</span>
...


<span class="code-comment">/*</span><span class="code-comment"> custom.c
 * (control implementation) */</span>
<span class="code-keyword">static</span> LRESULT CALLBACK
CustomProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    <span class="code-keyword">switch</span>(uMsg) {

        ...

        <span class="code-keyword">case</span> XXM_SOMESTRINGMESSAGEW:
            ... <span class="code-comment">//</span><span class="code-comment"> Handle input (WPARAM/LPARAM) as Unicode.</span>
            <span class="code-keyword">return</span> <span class="code-digit">0</span>;

        <span class="code-keyword">case</span> XXM_SOMESTRINGMESSAGEA:
            ... <span class="code-comment">//</span><span class="code-comment"> Handle input (WPARAM/LPARAM) as ANSI.</span>
                <span class="code-comment">//</span><span class="code-comment"> (Assuming the control holds the strings in Unicode,</span>
                <span class="code-comment">//</span><span class="code-comment"> this usually involves converting the string with</span>
                <span class="code-comment">//</span><span class="code-comment"> MultiByteToWideChar() (when string is input parameter)</span>
                <span class="code-comment">//</span><span class="code-comment"> or WideCharToMultiByte() (output parameter).</span>
            <span class="code-keyword">return</span> <span class="code-digit">0</span>;

        ...

    }
}</pre>

<p>Notifications handle the Unicode and ANSI strings yet differently and we will talk about it later by the end of this article.</p>

<h2>Control Creation and Destruction</h2>

<p>We already touched the topic of control creation and destruction in the <a href="http://www.codeproject.com/Articles/559385/Custom-Controls-in-Win32-API-The-Basics">1st part of this series</a>. However lets take a look on it a little bit closer.</p>

<p>The message <code>WM_NCCREATE</code> is the very first message the control gets during its life time. Correspondingly, the message <code>WM_NCDESTROY</code> is the last one. For custom control implementation, these messages are appropriate for allocation and setup of resources the control needs (e.g. some structure to hold the control's internal data and state), or freeing it respectively.</p>

<p>Note that for <code>WM_NCCREATE</code>, <code>DefWindowProc()</code> sets window text propagated from <code>CreateWindow()</code> via <code>LPARAM</code> as <code>CREATESTRUCT::lpszName</code>. If your control works with window text, you should propagate the message to <code>DefWindowProc()</code>. More about window text will be discussed later in a dedicated section later in this article.</p>

<p>During window creation, i.e. in the context of <code>CreateWindow()</code> (and assuming nothing fails during the creation), the messages <code>WM_NCCREATE</code> and <code>WM_CREATE</code> are sent. But some more messages can be sent between the two (typically, <code>WM_NCCALCSIZE</code>) and also after <code>WM_CREATE</code> (e.g. <code>WM_SIZE</code>, <code>WM_MOVE</code>, <code>WM_SHOWWINDOW</code>). Therefore, <code>WM_NCCREATE</code> should do the minimal work to have its data in a consistent state (that usually means allocating the structure for the state, and initializing it to some default values. That guarantees other message handlers can use the data without any problem.</p>

<p>As a rule of thumb, most of the other (less critical) setup of the control should be handled in <code>WM_CREATE</code>. So, for example, non-essential resources of the controls should be initialized to <code>NULL</code> in <code>WM_NCCREATE</code> and allocated thenafter in <code>WM_CREATE</code>. Especially if the resource allocation involves calling some other Win32API functions: They may resolve to sending another messages to the control and this design then guarantees the control data is in a consistent state and it helps to avoid subtle bugs. Some setup, can be deferred even further into other messages like <code>WM_SIZE</code> (e.g. if a complex control needs to compute some layout) and other appropriate message handlers.</p>

<p>When the window is being destroyed, i.e. in the context of <code>DestroyWindow()</code>, the control gets <code>WM_DESTROY</code> followed by <code>WM_NCDESTROY</code>. It is good practice to undo in <code>WM_NCDESTROY</code> what <code>WM_NCCREATE</code> did, and in <code>WM_DESTROY</code> what <code>WM_CREATE</code> did. I also recommend that <code>WM_DESTROY</code> keeps the control in consistent state, especially that all free'd pointers in <code>CustomData</code> structure are reset to <code>NULL</code>.</p>

<p><strong>Note:</strong> <code>WM_NCDESTROY</code> is sent even if previously the message <code>WM_NCCREATE</code> failed (i.e. if it returned <code>FALSE</code>). Also <code>WM_DESTROY</code> is sent even if <code>WM_CREATE</code> failed (i.e. returned <code>-1</code>). It has impact on error paths, as the code excerpt below demonstrates.</p>

<p>Special care must be taken if the control is implemented by customizing an existing window class. Therefore good practice is to call propagate <code>WM_NCCREATE</code> and <code>WM_CREATE</code> to original window procedure before handling it locally in the derived one. However that is another topic and we will explore this another time.</p>

<pre lang="C"><span class="code-comment">/*</span><span class="code-comment"> custom.c
 * (control implementation) */</span>

<span class="code-keyword">typedef</span> <span class="code-keyword">struct</span> CustomData_tag CustomData;
<span class="code-keyword">struct</span> CustomData_tag {
    HWND hwnd;
    HTHEME hTheme;
    <span class="code-comment">//</span><span class="code-comment"> ...</span>
};

<span class="code-keyword">static</span> LRESULT CALLBACK
CustomProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    CustomData* pData = (CustomData*) GetWindowLongPtr(hwnd, <span class="code-digit">0</span>);
    <span class="code-keyword">switch</span>(uMsg) {
        <span class="code-comment">//</span><span class="code-comment"> ...</span>

        <span class="code-keyword">case</span> WM_NCCREATE:
            <span class="code-keyword">if</span>(!DefWindowProc(hwnd, uMsg, wParam, lParam))
                <span class="code-keyword">return</span> FALSE;
            pData = malloc(<span class="code-keyword">sizeof</span>(CustomData));
            <span class="code-keyword">if</span>(pData == NULL)
                <span class="code-keyword">return</span> FALSE;
            ZeroMemory(pData, <span class="code-keyword">sizeof</span>(CustomData));
            pData-&gt;hwnd = hwnd;
            <span class="code-comment">//</span><span class="code-comment"> ... Set pData to consistent state (e.g. some reasnable default values)</span>
            SetWindowLongPtr(hwnd, <span class="code-digit">0</span>, (LONG_PTR)pData);
            <span class="code-keyword">return</span> TRUE;

        <span class="code-keyword">case</span> WM_CREATE:
        {
            LRESULT lres;
            lres = DefWindowProc(hwnd, uMsg, wParam, lParam);
            <span class="code-keyword">if</span>(lres == -<span class="code-digit">1</span>)
                <span class="code-keyword">return</span> -<span class="code-digit">1</span>;

            <span class="code-comment">//</span><span class="code-comment"> Further setup, e.g. opening theme handle if the control supports themed painting.</span>
            pData-&gt;hTheme = OpenThemeData(hwnd, L<span class="code-string">"</span><span class="code-string">..."</span>);
            <span class="code-comment">//</span><span class="code-comment"> ...</span>
            <span class="code-keyword">return</span> lres;
        }

        <span class="code-keyword">case</span> WM_DESTROY:
            <span class="code-keyword">if</span>(pData-&gt;hTheme != NULL) {
                CloseThemeData(pData-&gt;hTheme);
                pData-&gt;hTheme = NULL;
            }
            <span class="code-keyword">break</span>;

        <span class="code-keyword">case</span> WM_NCDESTROY:
            <span class="code-keyword">if</span>(pData != NULL) {  <span class="code-comment">//</span><span class="code-comment"> pData is NULL if WM_NCCREATE failed before SetWindowLongPtr()!!!</span>
                <span class="code-comment">//</span><span class="code-comment"> ... free all the other resources we alloc'ed in WM_NCCREATE</span>
                free(pData)
            }
            <span class="code-keyword">break</span>;
    }

    <span class="code-keyword">return</span> DefWindowProc(hwnd, uMsg, wParam, lParam);
}</pre>

<h2>Window Style and Extended Style</h2>

<p>Every window has a style and extended style associated with it. Both are actually double-word (<code>DWORD</code>) bitmasks, which augment look or behavior of the control. Initially the style and extended style are set accordingly to parameters of <code>CreateWindow()</code> or <code>CreateWindowEx()</code>. The style is propagated into <code>WM_NCCREATE</code> and <code>WM_CREATE</code> as members of <code>CREATESTRUCT</code>.</p>

<p>Later, during the control's life time, they can be changed with the function <code>SetWindowLong()</code>, using the indeces <code>GWL_STYLE</code> or <code>GWL_EXSTYLE</code> respectively.</p>

<p>All bits of the extended style and 16 higher bits of the style have a meaning defined by system. Lower 16 bit of the style are available for control-specific purposes.</p>

<p>The system-defined style and extended style bits are usually handled by appropriate messages passed to <code>DefWindowProc()</code>. For example, if the control has the style <code>WM_BORDER</code>, then handling of <code>WM_NCCALCSIZE</code>reserves the space for the border by making a client area of the control a bit smaller, and <code>WM_NCPAINT</code> paints into the space the border.</p>

<p>(Actually the border is then painted unthemed. We will eventually cover painting into non-client area and related stuff in some sequel article.)</p>

<p>Still, at least for the control-specific styles, the control implementation must know when the styles are changed to reflect it. Monitoring the changes in the style and extended style bits is performed with messages <code>WM_STYLECHANGING</code> and <code>WM_STYLECHANGED</code>. <code>WM_STYLECHANGING</code> is sent before the change is performed and the control may, if it desires so, deny the change or force a different change.</p>

<p>Although the control can always ask for the current style with <code>GetWindowLong()</code>, it can be often better and more convenient to have the style cached locally in our control's data structure, at least the low 16-bits of the style we (arguably) can need to access quite often.</p>

<pre lang="C"><span class="code-comment">/*</span><span class="code-comment"> custom.c
 * (control implementation) */</span>

<span class="code-keyword">typedef</span> <span class="code-keyword">struct</span> CustomData_tag CustomData;
<span class="code-keyword">struct</span> CustomData_tag {
    DWORD style : <span class="code-digit">16</span>;
    <span class="code-comment">//</span><span class="code-comment"> ...</span>
};

<span class="code-keyword">static</span> LRESULT CALLBACK
CustomProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    CustomData* pData = (CustomData*) GetWindowLongPtr(hwnd, <span class="code-digit">0</span>);
    <span class="code-keyword">switch</span>(uMsg) {
        <span class="code-comment">//</span><span class="code-comment"> ...</span>

        <span class="code-keyword">case</span> WM_NCCREATE:
        {
            CREATESTRUCT* cs = (CREATESTRUCT*) lParam;
            <span class="code-comment">//</span><span class="code-comment"> ...</span>
            pData-&gt;style = cs-&gt;style;
            <span class="code-keyword">return</span> TRUE;
        }

        <span class="code-keyword">case</span> WM_STYLECHANGING:
        {
            <span class="code-comment">/*</span><span class="code-comment"> Sometimes, for example, a control has to allow setting some style only
             * during its creation, and it needs to block the change of it thenafter.
             * It can be done by augmenting STYLESTRUCT::styleNew as we wish. */</span>
            <span class="code-keyword">if</span>(wParam == GWL_STYLE) {
                STYLESTRUCT* ss = (STYLESTRUCT*) lParam;

                <span class="code-comment">/*</span><span class="code-comment"> Prevent change in some styles we do not allow to change during control's life: */</span>
                <span class="code-keyword">if</span>((ss-&gt;styleOld ^ ss-&gt;styleNew) &amp; (XXS_CONSTSTYLE1 | XXS_CONSTSTYLE2)) {
                    ss-&gt;styleNew &amp;= ~(XXS_CONSTSTYLE1 | XXS_CONSTSTYLE2);
                    ss-&gt;styleNew |= ss-&gt;styleOld &amp; (XXS_CONSTSTYLE1 | XXS_CONSTSTYLE2);
                }
            }
            <span class="code-keyword">break</span>;
        }

        <span class="code-keyword">case</span> WM_STYLECHANGED:
            <span class="code-keyword">if</span>(wParam == GWL_STYLE) {
                STYLESTRUCT* ss = (STYLESTRUCT*) lParam;

                <span class="code-comment">/*</span><span class="code-comment"> Remember new style in our data structure for simple use */</span>
                pData-&gt;style = ss-&gt;styleNew;

                <span class="code-comment">/*</span><span class="code-comment"> If a style affecting look of the control changes, we may need to repaint it. */</span>
                <span class="code-keyword">if</span>((ss-&gt;styleOld ^ ss-&gt;styleNew) &amp; (XXS_ANOTHERLOOK | XXS_MORECOLOROUS)) {
                    <span class="code-keyword">if</span>(!pData-&gt;bNoRedraw)
                        InvalidateRect(hwnd, NULL, TRUE);
                }
            }
            <span class="code-keyword">break</span>;
    }

    <span class="code-keyword">return</span> DefWindowProc(hwnd, uMsg, wParam, lParam);
}</pre>

<h2>Window Geometry</h2>

<p>Whenever the control is created, resized, its (normal or extended) style is changed, or state of its status bars changes, the system sends <code>WM_NCCALCSIZE</code> to the control so that it can rearrange what portion of the control area is non-client or client one. The default implementation in <code>DefWindowProc()</code> reserves some space for borders, client edges and also scrollbars, depending on the style, extended style, and space needed for scrollbars (if any).</p>

<p>Custom implementation of this message may be quite complicated to all combinations of its parameters and return values it expects, but it is rarely needed, and the default implementation is almost always sufficient. The only exception may be when we want to say the system, what parts of the control's client area stays valid after the resize in cases when the rough control with class style <code>CS_HREDRAW</code> and <code>CS_VREDRAW</code> is not sufficient. In such cases the implementation may look like this:</p>

<pre lang="C"><span class="code-comment">/*</span><span class="code-comment"> custom.c
 * (control implementation) */</span>

<span class="code-keyword">static</span> LRESULT CALLBACK
CustomProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    CustomData* pData = (CustomData*) GetWindowLongPtr(hwnd, <span class="code-digit">0</span>);
    <span class="code-keyword">switch</span>(uMsg) {
        <span class="code-comment">//</span><span class="code-comment"> ...</span>

        <span class="code-keyword">case</span> WM_NCCALCSIZE:
            <span class="code-keyword">if</span>(wParam) {
                <span class="code-comment">//</span><span class="code-comment"> Return the desired combination of WVR_xxx constants, to</span>
                <span class="code-comment">//</span><span class="code-comment"> specify which part of client should be preserved after the</span>
                <span class="code-comment">//</span><span class="code-comment"> resize. For example:</span>
                <span class="code-keyword">return</span> WVR_ALIGNTOP | WVR_ALIGNRIGHT;
            }

            <span class="code-comment">//</span><span class="code-comment"> In other cases, pass the message into DefWindowProc().</span>
            <span class="code-keyword">break</span>;
    }

    <span class="code-keyword">return</span> DefWindowProc(hwnd, uMsg, wParam, lParam);
}</pre>

<p>After system knows what part of the control belongs to the non-client area, it sends <code>WM_MOVE</code> (if position of client area changed) and <code>WM_SIZE</code> (if size of it changed) to the control, and invalidates portions of client area accordingly to the return value of <code>WM_NCCALCSIZE</code>.</p>

<p>Whenever the control is to change its visibility, the control gets <code>WM_SHOWWINDOW</code>. That includes whenever <code>ShowWindow()</code> is called, but also when parent window gets minimized/restored, or when other window is maximized and hence it obscures the control completely. The cases can be distinguished by analyzing its parameters.</p>

<h2>Window Text</h2>

<p>For setting and retrieving a text associated with a window, Win32 API provides messages <code>WM_SETTEXT</code> and <code>WM_GETTEXT</code>. However applications usually do not use these messages directly and they call functions <code>SetWindowText()</code> and <code>GetWindowText()</code> which can convert the strings between Unicode and ANSI if caller and window opinion on type of strings does not match.</p>

<p>When passed into <code>DefWindowProc()</code>, the text is stored or retrieved directly from window manager. This allows Windows to get the text from a window belonging to another process, even if that other process is not responding. Raymond Chen described this nicely in his famous blog, The Old New Thing: <a href="http://blogs.msdn.com/b/oldnewthing/archive/2003/08/21/54675.aspx">The secret life of GetWindowText</a>.</p>

<p>It's also worth of note that for some utilities (e.g. various accessibility tools), the window text may ver useful even if no particular text is displayed by the control, so setting it to a reasonable value can improve an experience to users with some disabilities or limitations.</p>

<p>If you decide to handle the messages differently and (for example) store the text directly in your control's structure, then you should also consistently handle messages <code>WM_NCCREATE</code> and <code>WM_GETTEXTLENGTH</code>:</p>

<pre lang="C"><span class="code-comment">/*</span><span class="code-comment"> custom.c
 * (control implementation) */</span>

<span class="code-keyword">#include</span><span class="code-preprocessor"> <span class="code-keyword">&lt;</span><span class="code-leadattribute">tchar.h</span><span class="code-keyword">&gt;</span>
</span><span class="code-keyword">#include</span><span class="code-preprocessor"> <span class="code-keyword">&lt;</span><span class="code-leadattribute">strsafe.h</span><span class="code-keyword">&gt;</span>
</span>
<span class="code-keyword">typedef</span> <span class="code-keyword">struct</span> CustomData_tag CustomData;
<span class="code-keyword">struct</span> CustomData_tag {
    TCHAR* lpszText;
    <span class="code-comment">//</span><span class="code-comment"> ...</span>
};

<span class="code-keyword">static</span> LRESULT CALLBACK
CustomProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    CustomData* pData = (CustomData*) GetWindowLongPtr(hwnd, <span class="code-digit">0</span>);
    <span class="code-keyword">switch</span>(uMsg) {
        <span class="code-comment">//</span><span class="code-comment"> ...</span>

        <span class="code-keyword">case</span> WM_SETTEXT:
        {
            TCHAR* lpszText = (TCHAR*) lParam;
            TCHAR* lpszTmp;
            <span class="code-sdkkeyword">size_t</span> sz;

            <span class="code-keyword">if</span>(lpszText != NULL)
                StringCchLength(lpszText, STRSAFE_MAX_CCH, &amp;sz);
            <span class="code-keyword">else</span>
                sz = <span class="code-digit">0</span>;
            lpszTmp = (TCHAR*) malloc(<span class="code-keyword">sizeof</span>(TCHAR) * (sz+1));
            <span class="code-keyword">if</span>(lpszTmp == NULL)
                <span class="code-keyword">return</span> FALSE;
            StringCchCopyEx(lpszTmp, sz+1, lpszText, NULL, NULL, STRSAFE_IGNORE_NULLS);
            <span class="code-keyword">if</span>(pData-&gt;lpszText != NULL)
                free(pData-&gt;lpszText);
            pData-&gt;lpszText = lpszTmp;
            <span class="code-keyword">return</span> TRUE;
        }

        <span class="code-keyword">case</span> WM_GETTEXT:
        {
            <span class="code-sdkkeyword">size_t</span> sz = (<span class="code-sdkkeyword">size_t</span>) wParam;
            TCHAR* lpBuffer = (TCHAR*) lParam;
            TCHAR* lpEnd;

            <span class="code-keyword">if</span>(pData-&gt;lpszText == NULL)
                <span class="code-keyword">return</span> <span class="code-digit">0</span>;
            StringCchCopyEx(lpBuffer, sz, pData-&gt;lpszText, &amp;lpEnd, NULL, <span class="code-digit">0</span>);
            <span class="code-keyword">return</span> (lpEnd - lpBuffer);
        }

        <span class="code-keyword">case</span> WM_GETTEXTLENGTH:
        {
            <span class="code-sdkkeyword">size_t</span> sz;

            <span class="code-keyword">if</span>(pData-&gt;pszText == NULL)
                <span class="code-keyword">return</span> <span class="code-digit">0</span>;
            StringCchLength(pData-&gt;lpszText, STRSAFE_MAX_CCH, &amp;sz);
            <span class="code-keyword">return</span> sz;
        }

        <span class="code-keyword">case</span> WM_NCCREATE:
        {
            CRERATESTRUCT* cs = (CREATESTRUCT*) lParam;
            <span class="code-sdkkeyword">size_t</span> sz;
            <span class="code-comment">//</span><span class="code-comment"> ...</span>

            <span class="code-keyword">if</span>(cs-&gt;lpszText != NULL)
                StringCchLength(cs-&gt;lpszText, STRSAFE_MAX_CCH, &amp;sz);
            <span class="code-keyword">else</span>
                sz = <span class="code-digit">0</span>;
            pData-&gt;lpszText = (TCHAR*) malloc(<span class="code-keyword">sizeof</span>(TCHAR) * (sz+1));
            <span class="code-keyword">if</span>(pData-&gt;lpszText == NULL)
                <span class="code-keyword">return</span> FALSE;
            StringCchCopyEx(pData-&gt;lpszText, sz+1, cs-&gt;lpszText, NULL, NULL, STRSAFE_IGNORE_NULLS);
            <span class="code-keyword">return</span> TRUE;
        }

        <span class="code-keyword">case</span> WM_NCDESTROY:
            <span class="code-comment">//</span><span class="code-comment"> ...</span>
            <span class="code-keyword">if</span>(pData-&gt;lpszText != NULL)
                free(lpszText);
            <span class="code-comment">//</span><span class="code-comment"> ...</span>
            <span class="code-keyword">break</span>;
    }

    <span class="code-keyword">return</span> DefWindowProc(hwnd, uMsg, wParam, lParam);
}</pre>

<p><strong>Note:</strong> In most cases, relying on <code>DefWindowProc()</code> and calling <code>GetWindowText()</code> where neded (e.g. in painting code) fully suffices (and it is definitely less work). You should generally prefer this way unless you have good reason to do the stuff manually as the code excerpt shows.</p>

<h2>Window Font</h2>

<p>Every control which draws a text during its painting, should allow application to specify what font it should use. For this purpose the API provides the messages <code>WM_SETFONT</code> and <code>WM_GETFONT</code>. Their implementation is simple enough so there is no need for any further explanation:</p>

<pre lang="C"><span class="code-comment">/*</span><span class="code-comment"> custom.c
 * (control implementation) */</span>

<span class="code-keyword">typedef</span> <span class="code-keyword">struct</span> CustomData_tag CustomData;
<span class="code-keyword">struct</span> CustomData_tag {
    HFONT hFont;
    <span class="code-comment">//</span><span class="code-comment"> ...</span>
};

<span class="code-keyword">static</span> LRESULT CALLBACK
CustomProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    CustomData* pData = (CustomData*) GetWindowLongPtr(hwnd, <span class="code-digit">0</span>);
    <span class="code-keyword">switch</span>(uMsg) {
        <span class="code-comment">//</span><span class="code-comment"> ...</span>

        <span class="code-keyword">case</span> WM_SETFONT:
            pData-&gt;hFont = (HFONT) wParam;
            <span class="code-keyword">if</span>((BOOL) lParam  &amp;&amp; !pData-&gt;bNoRedraw)
                InvalidateRect(hwnd, NULL, TRUE);
            <span class="code-keyword">return</span> <span class="code-digit">0</span>;

        <span class="code-keyword">case</span> WM_GETFONT:
            <span class="code-keyword">return</span> (LRESULT) pData-&gt;hFont;
    }

    <span class="code-keyword">return</span> DefWindowProc(hwnd, uMsg, wParam, lParam);
}</pre>

<p>All what remains is the painting code to select the font into a device context when drawing a text. If the <code>hFont</code> is <code>NULL</code>, the control should use the font returned by <code>GetStockObject(SYSTEM_FONT)</code>. Note this font is pre-selected in new device contexts.</p>

<p>When painting text with <code>DrawThemeText()</code>, keep in mind the function paints with the font specified in the theme definition only if it defines one for the theme class/part/state combination. If it does not, the function uses the font selected into the device context. Hence, it is good idea to select the font into the device context even for the themed code path.</p>

<h2>Painting</h2>

<p>Window painting is based on handling <code>WM_ERASEBKGND</code>, <code>WM_PAINT</code> and <code>WM_PRINTCLIENT</code> we already described in <a href="http://www.codeproject.com/Articles/617212/Custom-Controls-in-Win32-API-The-Painting">one of the previous articles in the series</a>.</p>

<p>Aside that, there is also a message <code>WM_SETREDRAW</code> which is supported by many standard controls. The message allows application to temporarily disable the redrawing of the control when its state changes. This is, for example, often used for controls like list view and tree view. Often, application may need to populate such controls with huge number of items, and the control refreshes itself after each such insert to reflect the data it holds.</p>

<p>If the application knows it inserts hundreds of items at once, it may disable the repaint, insert all the items, re-enable the repaint and force the repaint:</p>

<pre><span class="code-comment">/*</span><span class="code-comment"> app.c
 * (some application) */</span>

...

SendMessage(hwnd, WM_SETREDRAW, FALSE, <span class="code-digit">0</span>);  <span class="code-comment">//</span><span class="code-comment"> Disable repaint</span>
...  <span class="code-comment">//</span><span class="code-comment"> Huge number of messages which change control's state</span>
SendMessage(hwnd, WM_SETREDRAW, TRUE, <span class="code-digit">0</span>);   <span class="code-comment">//</span><span class="code-comment"> Re-enable repaint</span>
RedrawWindow(hwnd, NULL, NULL, RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);</pre>

<p><strong>Note:</strong> Complex controls may need to repaint also its child windows or their non-client area, hence we used <code>RedrawWindow()</code> with all the flags instead of simple <code>InvalidateRect(hwnd, NULL, TRUE)</code>. However if it is known there are no children or frame, <code>InvalidateRect()</code> would suffice.</p>

<p>If you want to support this message (which you should if setting up or populating the control might lead to too many repaints), then on the control's implementation side, it usually means just remembering a single flag in control's data and invalidating the control's area only when the flag is not set:</p>

<pre lang="C"><span class="code-comment">/*</span><span class="code-comment"> custom.c
 * (control implementation) */</span>

<span class="code-keyword">typedef</span> <span class="code-keyword">struct</span> CustomData_tag CustomData;
<span class="code-keyword">struct</span> CustomData_tag {
    <span class="code-comment">//</span><span class="code-comment"> Note the inverted logic of this meber.</span>
    <span class="code-comment">//</span><span class="code-comment"> I.e. ZeroMemory() in WM_NCCREATE sets it correctly to FALSE.</span>
    BOOL bNoRedraw;

    <span class="code-comment">//</span><span class="code-comment"> ...</span>
};

<span class="code-keyword">static</span> LRESULT CALLBACK
CustomProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    CustomData* pData = (CustomData*) GetWindowLongPtr(hwnd, <span class="code-digit">0</span>);
    <span class="code-keyword">switch</span>(uMsg) {
        <span class="code-comment">//</span><span class="code-comment"> ...</span>

        <span class="code-keyword">case</span> WM_PAINT:
        {
            <span class="code-comment">//</span><span class="code-comment"> Adapted WM_PAINT handler from the article about painting.</span>
            <span class="code-comment">//</span><span class="code-comment"> We only added the test for pData-&gt;bNoRedraw.</span>
            PAINTSTRUCT ps;
            BeginPaint(hwnd, &amp;ps);
            <span class="code-keyword">if</span>(!pData-&gt;bNoRedraw) {
                <span class="code-keyword">if</span>(GetWindowLong(hwnd, GWL_STYLE) &amp; XXS_DOUBLEBUFFER)
                    CustomDoubleBuffer(hwnd, &amp;ps);
                <span class="code-keyword">else</span>
                    CustomPaint(hwnd, ps.hdc, &amp;ps.rcPaint, ps.fErase);
            }
            EndPaint(hwnd, &amp;ps);
            <span class="code-keyword">return</span> <span class="code-digit">0</span>;
        }

        <span class="code-keyword">case</span> WM_SETREDRAW:
            pData-&gt;bNoRedraw = !wParam;
            <span class="code-keyword">if</span>(!pData-&gt;bNoRedraw)        <span class="code-comment">//</span><span class="code-comment"> Repaint automatically on re-enabling.</span>
                InvalidateRect(hwnd, NULL, TRUE);
            <span class="code-keyword">return</span> <span class="code-digit">0</span>;

        <span class="code-keyword">case</span> XXM_CHANGESTATE:
            ...  <span class="code-comment">//</span><span class="code-comment"> modify control's state by modifying data in pData</span>
                 <span class="code-comment">//</span><span class="code-comment"> (e.g. insert/set/delete items of any kind in it).</span>

            <span class="code-keyword">if</span>(!pData-&gt;bNoRedraw)        <span class="code-comment">//</span><span class="code-comment"> Avoid repaint when disabled by the app.</span>
                InvalidateRect(hwnd, NULL, TRUE);
            <span class="code-keyword">return</span> <span class="code-digit">0</span>;
    }

    <span class="code-keyword">return</span> DefWindowProc(hwnd, uMsg, wParam, lParam);
}</pre>

<p><strong>Note:</strong> According to MSDN, when repainting is re-enabled, application itself is then supposed to invalidate the control's area and repaint. However many standard controls do that automatically. I decided to follow the practice in the example above. The advantage of this approach also is the control may have better idea what exactly needs to repaint so it may be able to invalidate only relevant parts of its area.</p>

<p>I recommend another post on The Old New Thing blog as a further complementary reading on the topic of <code>WM_SETREDRAW</code>: <a href="http://blogs.msdn.com/b/oldnewthing/archive/2011/01/24/10119211.aspx">There's a default implementation for WM_SETREDRAW, but you might be able to do better</a>.</p>

<p>Yet another message related to painting is <code>WM_NCPAINT</code>. We will cover it in another article, which will talk about, so lets skip it for now.</p>

<h2>Interaction with Dialog</h2>

<p>Quite often, the parent window of the control is a dialog. The dialogs are quite popular also for simplicity of their indirect creation by using a dialog template (<code>DIALOG</code> or <code>DIALOGEX</code> resource), as it automates a lot of code for creation larger number of windows manually. Of course, the dialog template, or its items respectively, can refer to the control's window class.</p>

<p><strong>Note:</strong> The dialog template can refer to the control's class name only if it has been registered with the same instance handle (<code>HINSTANCE</code>) where the template lives, or if the class is global (i.e. class style <code>CS_GLOBAL</code> has been used).</p>

<p>Normal behavior of dialog is determined by its dialog procedure, which is usually the same code which is externally available by calling <code>DefDlgProc()</code>, so customized dialogs can propagate messages to it in a similar way as window procedure do it with <code>DefWindowProc()</code>.</p>

<p>Dialogs, in general, provide some features for user's comfort and effectiveness. Some of them need cooperation from the control to work well. These features are provided by <code>DefDlgProc()</code>, which is usually called from the dialog's procedure. Application can also emulate some of those features for normal (non-dialog) windows. For example refer to Raymond Chanin's another post: <a href="http://blogs.msdn.com/b/oldnewthing/archive/2003/10/21/55384.aspx">Using the TAB key to navigate in non-dialogs</a>.</p>

<p>So lets take a look how make the control ready for such coopertion.</p>

<p>The dialog resource can specify the font to be used. If so, the dialog procedure sends <code>WM_SETFONT</code> to each control it creates. We already talked about this message earlier, so lets go on.</p>

<p>Another important feature of dialog is keyboard navigation. Users often rely on changing focus of their controls by pressing <em>TAB</em> or <em>SHIFT+TAB</em> hot keys. The dialog procedure can use also use other keys as <em>space</em> or <em>enter</em>. Therefore it is important to tell the dialog what keys your control needs to get for its own operation, so the dialog knows whether it may use it for the navigation or whether he should feed the control with it. This is done by handling <code>WM_GETDLGCODE</code>.</p>

<p>The handler of this messages is usually just one-liner which specifies bitmask describing the control's needs:</p>

<pre lang="C"><span class="code-comment">/*</span><span class="code-comment"> custom.c
 * (control implementation) */</span>

<span class="code-keyword">typedef</span> <span class="code-keyword">struct</span> CustomData_tag CustomData;
<span class="code-keyword">struct</span> CustomData_tag {
    BOOL bNoRedraw;  <span class="code-comment">//</span><span class="code-comment"> inverted logic, i.e. ZeroMemory() WM_NCCREATE leaves this on the right default.</span>
    <span class="code-comment">//</span><span class="code-comment"> ...</span>
};

<span class="code-keyword">static</span> LRESULT CALLBACK
CustomProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    CustomData* pData = (CustomData*) GetWindowLongPtr(hwnd, <span class="code-digit">0</span>);
    <span class="code-keyword">switch</span>(uMsg) {
        <span class="code-comment">//</span><span class="code-comment"> ...</span>

        <span class="code-keyword">case</span> WM_GETDLGCODE:
            <span class="code-keyword">return</span> DLGC_flag1 | DLGC_flag2;
            <span class="code-comment">//</span><span class="code-comment"> For illustrative purpose only. Refer to MSDN for all possible flags and their meaning.</span>
    }

    <span class="code-keyword">return</span> DefWindowProc(hwnd, uMsg, wParam, lParam);
}</pre>

<p>Yet another feature is a visual feedback of focus and accelerator keys in the dialog's appearance. Historically these were always shown. But since Windows XP, Microsoft has decided it may be disturbing for users who use mostly mouse and rarely use keyboard. So, Windows started to hide the focus rect and accelerator key mark by default, unless user starts to navigate by the keyboard. As an end user you may like it or dislike it, as a developer you should make the control to follow it. Users who do not like it, can then disable the hiding in Control Panels.</p>

<p>The logic is based on handling of the message <code>WM_UPDATEUISTATE</code> by every control which can have focus or a shortcut. When handled manually, it may be implemented like this:</p>

<pre lang="C"><span class="code-comment">/*</span><span class="code-comment"> custom.c
 * (control implementation) */</span>

<span class="code-keyword">typedef</span> <span class="code-keyword">struct</span> CustomData_tag CustomData;
<span class="code-keyword">struct</span> CustomData_tag {
    DWORD dwUiState;
    <span class="code-comment">//</span><span class="code-comment"> ...</span>
};

<span class="code-keyword">static</span> LRESULT CALLBACK
CustomProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    CustomData* pData = (CustomData*) GetWindowLongPtr(hwnd, <span class="code-digit">0</span>);
    <span class="code-keyword">switch</span>(uMsg) {
        <span class="code-comment">//</span><span class="code-comment"> ...</span>

        <span class="code-keyword">case</span> WM_UPDATEUISTATE:
            <span class="code-keyword">switch</span>(LOWORD(wParam)) {
                <span class="code-keyword">case</span> UIS_CLEAR:       pData-&gt;dwUiState &amp;= ~HIWORD(wp); <span class="code-keyword">break</span>;
                <span class="code-keyword">case</span> UIS_SET:         pData-&gt;dwUiState |= HIWORD(wp); <span class="code-keyword">break</span>;
                <span class="code-keyword">case</span> UIS_INITIALIZE:  pData-&gt;dwUiState = HIWORD(wp); <span class="code-keyword">break</span>;
            }
            <span class="code-keyword">if</span>(!pData-&gt;bNoRedraw)
                InvalidateRect(hwnd, NULL, FALSE);
            <span class="code-keyword">break</span>;
    }

    <span class="code-keyword">return</span> DefWindowProc(hwnd, uMsg, wParam, lParam);
}</pre>

<p>The rest is then just following the flags in your painting code. For example, if the condition <code>(pData-&gt;dwUiState &amp; UISF_HIDEACCEL)</code> stands, you should reflect it by using <code>DT_HIDEPREFIX</code> flag in <code>DrawText()</code>.</p>

<p>Or, you may rely on implementation of the message in <code>DefWindowProc()</code> and only query the current state by sending the control <code>WM_QUERYUISTATE</code> in the painting code.</p>

<p>Once again, further recommended complementary reading consists of some posts on The Old New Thing:</p>

<ul>
	<li><a href="http://blogs.msdn.com/b/oldnewthing/archive/2005/05/03/414317.aspx">Managing the UI state of accelerators and focus rectangles</a></li>	<li><a href="http://blogs.msdn.com/b/oldnewthing/archive/2013/05/16/10419105.aspx">Untangling the confusingly-named WM_UPDATEUISTATE and WM_CHANGEUISTATE messages</a></li>	<li><a href="http://blogs.msdn.com/b/oldnewthing/archive/2013/05/17/10419502.aspx">Who sends the initial WM_UPDATEUISTATE message?</a></li></ul>

<h2>Interaction with System</h2>

<p>The control also may need to handle some messages informing it about changes in some Windows settings which may have impact on controls and their look or behavior.</p>

<p>One such message is <code>WM_SYSCOLORCHANGE</code> sent by system to all top-level windows whenever the colors as returned by <code>GetSysColor()</code> change. The top-level windows should distribute the message to all child windows, including our control. (<strong>Gotcha:</strong> it is on app's developers. AFAIK, <code>DefWindowProc()</code> does not do that.) If the control's painting depends on system colors, it should repaint itself with new ones.</p>

<p>Another message with a bit similar purpose is <code>WM_THEMECHANGED</code> which is sent when the theme preferences are changed. Again the control should repaint itself with new theme data, which requires reopening the theme handles. We already discussed this in the previous article.</p>

<h2>Monitoring Focus</h2>

<p>Often, the control needs to repaint itself when it gets or loses focus. This is very simply done by tracking <code>WM_SETFOCUS</code> and <code>WM_GETFOCUS</code> messages.</p>

<pre lang="C"><span class="code-comment">/*</span><span class="code-comment"> custom.c
 * (control implementation) */</span>

<span class="code-keyword">static</span> LRESULT CALLBACK
CustomProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    CustomData* pData = (CustomData*) GetWindowLongPtr(hwnd, <span class="code-digit">0</span>);
    <span class="code-keyword">switch</span>(uMsg) {
        <span class="code-comment">//</span><span class="code-comment"> ...</span>

        <span class="code-keyword">case</span> WM_SETFOCUS:
        <span class="code-keyword">case</span> WM_GETFOCUS:
            <span class="code-keyword">if</span>(!pData-&gt;bNoRedraw)
                InvalidateRect(hwnd, NULL, FALSE);
            <span class="code-keyword">break</span>;
    }

    <span class="code-keyword">return</span> DefWindowProc(hwnd, uMsg, wParam, lParam);
}</pre>

<h2>Keyboard Messages</h2>

<p>There is a lot of messages for handling a keyboard, so lets introduce them.</p>

<p>At the low level, there are <code>WM_KEYDOWN</code> and <code>WM_KEYUP</code> messages. The former of them, as the name of it suggests, is sent when you press a key on your keyboard, but also when you keep holding it down and key auto-repeat kicks in (you can distinguish the two cases by inspecting its params). The latter one is sent when the key is released.</p>

<p>On top of that, there is <code>WM_CHAR</code> (or <code>WM_DEADCHAR</code>). Some of them may be sent between <code>WM_KEYDOWN</code> and <code>WM_KEYUP</code>, with translated identification of virtual key code to a real character. The translation is done in the application's message loop by calling the function <code>TranslateMessage()</code>. When the function sees <code>WM_KEYDOWN</code>, it just inserts corresponding <code>WM_CHAR</code> which is then retrieved later by another call of <code>GetNextMessage()</code>.</p>

<p><strong>Note:</strong> It really matters whether you handle the lower level or higher level messages. The message translation involves a configuration of keyboard and its layout. It is also affected by state of caps lock, shift or other functional keys. If you are developing a game, you probably are more interested in <code>WM_KEYDOWN</code> and <code>WM_KEYUP</code>. If it is a text editor, then it is more likely <code>WM_CHAR</code> for handling normal text typing and <code>WM_KEYDOWN</code> and <code>WM_KEYUP</code> to handle some functional keys like <em>&lt;INSERT&gt;</em> or cursor arrow keys.</p>

<p>Most of the keyboard messages mentioned above also have their <em>SYS</em> counterpart: <code>WM_SYSKEYDOWN</code>, <code>WM_SYSKEYUP</code> and <code>WM_SYSCHAR</code>. Actually these are sent in the same situations, but for key combinations usually used for tasks defined by Windows. E.g. combinations with <em>&lt;ALT&gt;</em> to enter window menu etc. Handling them allows you to override the default handling (assuming you do not pass them into <code>DefWindowProc()</code>). Under normal circumstances, this separation allows you to focus on handling the non-SYS messages and keeping these on <code>DefWindowProc()</code>, without a fear of any conflict.</p>

<p>Additionally there is a message <code>WM_UNICHAR</code> which is capable to handle any UTF-32 Unicode code point. As Windows internally works in <code>UTF-16</code> (with support of surrogate pairs since Windows XP), the system never sends this message to you. It is rather for your own comfort: If it is beneficial to support the message you can implement it in your window procedure and you as well as 3rd party applications (typically various Input Method Editors for e.g. Asian languages) can send it to you.</p>

<p>Some more in-depth reading about handling keyboard messages can be found in the article <a href="http://www.ngedit.com/a_wm_keydown_wm_char.html">What's broken in the WM_KEYDOWN-WM_CHAR input model?</a>, despite its pessimistic title.</p>

<h2>Mouse Messages</h2>

<p>Mouse handling involves even more messages. There are messages for handling move of a mouse pointer (<code>WM_MOVE</code>), actions with mouse buttons (e.g. <code>WM_LBUTTONDOWN</code> for left button down), and messages for composed actions like click or double click (e.g. <code>WM_LBUTTONDBLCLK</code>). Most messages also have two flavors: normal (client) and non-client whose names begin with <code>WM_NC</code> (e.g. <code>WM_NCMOUSEMOVE</code>, <code>WM_NCNCBUTTONUP</code>).</p>

<p>The normal messages are sent when the mouse event occurs while the mouse pointer is in a client area of the control, or while <em>mouse capture</em> is in an effect: The control may, depending on its logic, ask the system to send all mouse messages to it with the function <code>SetCapture()</code>, until it releases it with <code>ReleaseCapture()</code> (or until another window steals the capture with the <code>SetCapture()</code>. When the control loses the capture, it is notified with <code>WM_RELEASEDCAPTURE</code>.) The "NC" messages are sent when the mouse operation happens in non-client area (and the capture is not in effect).</p>

<p>The mouse capture is frequently used, for example, when implementing a button-like control (or a control whose part is of button-like nature). When its button is pressed (<code>WM_LBUTTONDOWN</code>), you take the capture so subsequent button release goes to the control even when it occurs outside of the control's client area:</p>

<pre lang="C"><span class="code-comment">/*</span><span class="code-comment"> custom.c
 * (control implementation) */</span>

<span class="code-keyword">typedef</span> <span class="code-keyword">struct</span> CustomData_tag CustomData;
<span class="code-keyword">struct</span> CustomData_tag {
    BOOL bLeftButtonPressed;
    <span class="code-comment">//</span><span class="code-comment"> ...</span>
};


<span class="code-keyword">static</span> LRESULT CALLBACK
CustomProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    CustomData* pData = (CustomData*) GetWindowLongPtr(hwnd, <span class="code-digit">0</span>);
    <span class="code-keyword">switch</span>(uMsg) {
        <span class="code-comment">//</span><span class="code-comment"> ...</span>

        <span class="code-keyword">case</span> WM_LBUTTONDOWN:
            pData-&gt;bLeftButtonPressed = TRUE;
            SetCapture(hwnd);
            <span class="code-keyword">break</span>;

        <span class="code-keyword">case</span> WM_LBUTTONUP:
        {
            POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
            RECT rc;
            GetClientArea(hwnd, &amp;rc);
            <span class="code-keyword">if</span>(PtInRect(&amp;rc, pt))
                SendMessage(GetParent(hwnd), WM_COMMAND, GetWindowLong(hwnd, GWL_ID), <span class="code-digit">0</span>);
            ReleaseCapture();
        }
            <span class="code-comment">//</span><span class="code-comment"> No break here, fall through</span>

        <span class="code-keyword">case</span> WM_RELEASEDCAPTURE:
            pData-&gt;bLeftButtonPressed = FALSE;
            <span class="code-keyword">break</span>;
    }

    <span class="code-keyword">return</span> DefWindowProc(hwnd, uMsg, wParam, lParam);
}</pre>

<p><strong>Note:</strong> When the mouse capture is in effect, the window it holds it gets <strong>all</strong> mouse messages. So depending on its logic, for some of them, the control may need to manually check whether a mouse message really occurred inside it or not.</p>

<p>It is also important to remember that many messages are sent only when you explicitly ask for them: Double-click messages (<code>WM_LBUTTONDBLCLK</code>, <code>WM_RBUTTONDBLCK</code> etc.) are sent only if the window class was registered with the class style <code>CS_DBLCLKS</code>.</p>

<p>Messages <code>WM_MOUSELEAVE</code> and <code>WM_MOUSEHOVER</code> are sent only when their tracking is enabled with <code>TrackMouseEvent()</code>. Note the function enables one shot of the messages, and that <code>WM_MOUSELEAVE</code> disables the tracking altogether, so, usually, the function needs to be called again:</p>

<pre lang="C"><span class="code-comment">/*</span><span class="code-comment"> custom.c
 * (control implementation) */</span>

<span class="code-keyword">typedef</span> <span class="code-keyword">struct</span> CustomData_tag CustomData;
<span class="code-keyword">struct</span> CustomData_tag {
    BOOL fTrackingMouse;
    <span class="code-comment">//</span><span class="code-comment"> ...</span>
};

<span class="code-keyword">static</span> <span class="code-keyword">void</span>
TrackMouse(HWND hwnd)
{
    TRACKMOUSEEVENT tme;
    tme.cbSize = <span class="code-keyword">sizeof</span>(TRACKMOUSEEVENT);
    tme.dwFlags = TME_LEAVE | TME_HOVER;
    tme.hwndTrack = hwnd;
    tme.dwHoverTime = HOVER_DEFAULT;
    TrackMouseEvent(&amp;tme);
}

<span class="code-keyword">static</span> LRESULT CALLBACK
CustomProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    CustomData* pData = (CustomData*) GetWindowLongPtr(hwnd, <span class="code-digit">0</span>);
    <span class="code-keyword">switch</span>(uMsg) {
        <span class="code-comment">//</span><span class="code-comment"> ...</span>

        <span class="code-keyword">case</span> WM_MOUSEMOVE:
            <span class="code-keyword">if</span>(!pData-&gt;fTrackingMouse) {
                TrackMouse();
                pData-&gt;fTrackingMouse = TRUE;
            }
            <span class="code-keyword">break</span>;

        <span class="code-keyword">case</span> WM_MOUSEHOVER:
            ... <span class="code-comment">//</span><span class="code-comment"> handle mouse hover (often used for example to show a tooltip)</span>
            TrackMouse();
            <span class="code-keyword">break</span>;

        <span class="code-keyword">case</span> WM_MOUSELEAVE:
            pData-&gt;fTrackingMouse = FALSE;
            ...  <span class="code-comment">//</span><span class="code-comment"> handle mouse leave</span>
            <span class="code-keyword">break</span>;
    }

    <span class="code-keyword">return</span> DefWindowProc(hwnd, uMsg, wParam, lParam);
}</pre>

<p>Also note there is no <code>WM_MOUSEENTER</code> message. You can use <code>WM_MOUSEMOVE</code> for this purpose: Whenever <code>WM_MOUSEMOVE</code> comes and the flag <code>fTrackingMouse</code> is not set, then the mouse entered the client area of the window.</p>

<h2>Scrolling Messages</h2>

<p>There are some message that allow controls to support scrolling: <code>WM_HSCROLL</code>, <code>WM_VSCROLL</code>, <code>WM_MOUSEWHEEL</code> and <code>WM_MOUSEHWHEEL</code>. However we'll take a closer look on scrolling in some sequel article.</p>

<h2>Accessibility</h2>

<p>Actually, the controls should also support cooperation with accessiblity and automation tools. It is done by handling <code>WM_GETOBJECT</code>, which is supposed to return pointer to a COM objects implementing certain COM interface (depending on <code>WPARAM</code> and <code>LPARAM</code>).</p>

<p>This is, however, quite complex topic. In addition, I admit it is a topic I cannot say much about currently due my limited knowledge about it. Hopefully we will return to it sometime later.</p>

<h2>Notifications</h2>

<p>So far, we mainly talked about situation when system or application needs to talk to the control. But often, the control also needs to tell something about its change to the application. That is usually done through some of notification message.</p>

<p>There are two main notification messages: <code>WM_COMMAND</code> and <code>WM_NOTIFY</code>. The first one is unable to bear more data then just an identification of control it is sending it (i.e. our control) and a 16-bit value which can be packed to it. Therefore it is typical use case is to trigger some action. For example, standard buttons fire <code>WM_COMMAND</code> when clicked.</p>

<p>The latter message, <code>WM_NOTIFY</code>, bears more data, and additionally it is further extensible. The parameter <code>LPARAM</code> is actually a pointer to <code>NMHDR</code> structure, or any other (control and notification-code specific) structure with any additionally data. The control just has to guarantee any such custom structure begins with <code>NMHDR</code>:</p>

<pre lang="C"><span class="code-comment">/*</span><span class="code-comment"> custom.h
 * (public control interface) */</span>


<span class="code-comment">//</span><span class="code-comment"> Notification code</span>
<span class="code-preprocessor">#define XXN_MYNOTIFICATION    101
</span>
<span class="code-keyword">typedef</span> <span class="code-keyword">struct</span> XXNM_NOTIFICATIONDATA {
    NMHDR hdr; <span class="code-comment">//</span><span class="code-comment"> NMHDR has to be the 1st member of the struct.</span>
    ...        <span class="code-comment">//</span><span class="code-comment"> Other data.</span>
} XXNM_NOTIFICATIONDATA;

<span class="code-comment">/*</span><span class="code-comment"> custom.c
 * (control implementation) */</span>

<span class="code-keyword">static</span> <span class="code-keyword">void</span>
SendNotification(HWND hwnd)
{
    XXNM_NOTIFICATIONDATA nd;

    nd.hdr.hwndFrom = hwnd;
    nd.hdr.idFrom = GetWindowLong(hwnd, GWL_ID);
    nd.hdr.code = XXN_MYNOTIFICATION;
    ... <span class="code-comment">//</span><span class="code-comment"> setup the other struct members</span>
    SendMessage(GetParent(hwnd), WM_NOTIFY, nd.hdr.idFrom, (LPARAM) &amp;nd);
}</pre>

<p>However, there is one more complication in case when the structure contains strings. The control is responsible to provide the strings in encoding the parent window expects. If the parent window is not under your control, i.e. when you cannot be sure what the parent wants, you have to ask it with the message <code>WM_NOTIFYFORMAT</code>, either each time before sending such message, or when the control is created and then every time we are asked to refresh the info:</p>

<pre lang="C"><span class="code-comment">/*</span><span class="code-comment"> custom.c
 * (control implementation) */</span>

<span class="code-keyword">typedef</span> <span class="code-keyword">struct</span> CustomData_tag CustomData;
<span class="code-keyword">struct</span> CustomData_tag {
    BOOL fUnicodeNotifications;
    <span class="code-comment">//</span><span class="code-comment"> ...</span>
};

<span class="code-keyword">static</span> LRESULT CALLBACK
CustomProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    CustomData* pData = (CustomData*) GetWindowLongPtr(hwnd, <span class="code-digit">0</span>);
    <span class="code-keyword">switch</span>(uMsg) {
        <span class="code-comment">//</span><span class="code-comment"> ...</span>

        <span class="code-keyword">case</span> WM_NOTIFYFORMAT:
        {
            LRESULT format;
            <span class="code-keyword">if</span>(lParam == NF_REQUERY) {
                format = SendMessage(cs-&gt;hwndParent, WM_NOTIFYFORMAT, (WPARAM) hwnd, NF_QUERY);
                pData-&gt;fUnicodeNotifications = (format == NFR_UNICODE);
            } <span class="code-keyword">else</span> {
                format = (pData-&gt;fUnicodeNotifications ? NFR_UNICODE : NFR_ANSI);
            }
            <span class="code-keyword">return</span> format;
        }

        <span class="code-keyword">case</span> WM_NCCREATE:
        {
            CREATESTRUCT* ss = (CREATESTRUCT*) lParam;
            LRESULT format;
            <span class="code-comment">//</span><span class="code-comment"> ...</span>

            format = SendMessage(cs-&gt;hwndParent, WM_NOTIFYFORMAT, (WPARAM) hwnd, NF_QUERY);
            pData-&gt;fUnicodeNotifications = (format == NFR_UNICODE);
            <span class="code-keyword">return</span> TRUE;
        }
    }

    <span class="code-keyword">return</span> DefWindowProc(hwnd, uMsg, wParam, lParam);
}</pre>

<h2>Downloadable Example</h2>

<p>The attached example project (at the top of this page) implements a button. It roughly corresponds to standard button with <code>BS_PUSHBUTTON</code> or <code>BS_DEFPUSHBUTTON</code> style. Sure, such code is not useful for reuse in any application as you can simply stick with the standard button.</p>

<p>But still, the code of the custom control demonstrates handling of good portion of the messages described in this article as well as the stuff what we already learnt in the previous articles about painting and visual styles, so it can serve as a code for your further experimenting.</p>

<p>The example application is made of a simple dialog with two buttons: one standard button and one of the custom control implementation, so you can compare them live. The only main difference is that (with default Aero Theme) on Windows Vista and later the real button uses transition animation when changing state (e.g. between hot and normal). Some of the sequel articles will be dedicated to several methods of control animations so surely we will fill this gap later.</p>

<h2>Real World Code</h2>

<p>Today's real world code for further studying consists from few <a href="http://www.winehq.org/">Wine</a> sources. It may give you good insight what those function expect from various standard messages.</p>

<ul>
	<li>Implementation of <code>DefWindowProc()</code>: <a href="https://github.com/mirrors/wine/blob/master/dlls/user32/defwnd.c">https://github.com/mirrors/wine/blob/master/dlls/user32/defwnd.c</a></li>	<li>Implementation of <code>DefDlgProc()</code>: <a href="https://github.com/mirrors/wine/blob/master/dlls/user32/defdlg.c">https://github.com/mirrors/wine/blob/master/dlls/user32/defdlg.c</a></li>	<li>Implementation of <code>CreateWindow()</code>: <a href="https://github.com/mirrors/wine/blob/master/dlls/user32/win.c">https://github.com/mirrors/wine/blob/master/dlls/user32/win.c</a></li></ul>

<p><strong>Note:</strong> Keep in mind that some messages not essential for running Windows applications are not (yet) implemented in Wine. For example, the code above does not play with <code>WM_UPDATEUISTATE</code> and its relatives.</p>

<h2>Next Time: Adapting Existing Controls</h2>

<p>Often, creating new control by adapting an existing one can be much less work then implementing it from scratch. Next time, we will explore few techniques how to do that and what advantages or limitations they bear.</p>


						</div>
						

						<div class="float-right" style="margin:20px 0 0 10px;border:1px solid #ccc">
						
						</div>
                        
                        
						
						<h2>License</h2>
						<div id="LicenseTerms"><p>This article, along with any associated source code and files, is licensed under <a href="http://www.codeproject.com/info/cpol10.aspx" rel="license">The Code Project Open License (CPOL)</a></p></div><h2 id="ctl00_AboutHeading">About the Author</h2>
						    

<div class="author-wrapper">

    <div class="pic-wrapper"> 
        <img id="ctl00_AboutAuthorRptr_ctl00_AboutAuthor_memberPhoto" class="profile-pic" src="./Custom Controls in Win32 API_ Standard Messages - CodeProject_files/58de2d085c17e28b8951315245dd408c.jpeg" style="border-width:0px;transform:rotate(1deg);">
    </div>

    <div class="container-member">  
        <b><a id="ctl00_AboutAuthorRptr_ctl00_AboutAuthor_memberProfileLink" class="author" href="https://www.codeproject.com/Members/Martin-Mitas">Martin Mitáš</a></b>

        <table>
        <tbody><tr>
            <td rowspan="2" nowrap="" valign="middle">
            <div id="ctl00_AboutAuthorRptr_ctl00_AboutAuthor_FollowOn" class="follow">
	            
	            
	            <a href="https://www.linkedin.com/profile/view?id=88607525"><img style="vertical-align:middle;border:0;height:24px;width:24px" alt="LinkedIn" src="./Custom Controls in Win32 API_ Standard Messages - CodeProject_files/linkedin-32.png"></a> 
            </div>
            </td>
            <td nowrap="nowrap">
                <div class="company">
                    <span id="ctl00_AboutAuthorRptr_ctl00_AboutAuthor_memberJobTitle">Team Leader</span>
	                <span id="ctl00_AboutAuthorRptr_ctl00_AboutAuthor_memberCompany"></span>
                </div>
            </td>
            <td rowspan="2" style="padding-left:15px">
                <a id="ctl00_AboutAuthorRptr_ctl00_AboutAuthor_FollowMember_FollowBtn" title="Have events related to this Member appear in your timeline" class="button unfollowed align-center invisible" data-enabletooltip="true" data-tooltip="Have the articles and posts from this member appear in your Timeline so you can stay up to date." style="display:none;">Follow<div class="tiny-text" style="margin-top:-3px;">this Member</div></a>
	<a id="ctl00_AboutAuthorRptr_ctl00_AboutAuthor_FollowMember_UnfollowBtn" title="Unfollow this Member" class="button followed align-center invisible" data-enabletooltip="true" data-tooltip="Stop following this Member" style="display:none;">Unfollow</a>

            </td>
        </tr>
        <tr>
            <td>
                <span id="ctl00_AboutAuthorRptr_ctl00_AboutAuthor_memberLocation">Czech Republic <img src="./Custom Controls in Win32 API_ Standard Messages - CodeProject_files/CZ.gif" alt="Czech Republic" width="16px" height="11px"></span>
            </td>
        </tr>
        </tbody></table>
    </div>

    <div class="description">
        No Biography provided

        
    </div>

</div><br>
						
						

						<div class="clearfix"></div>

						<div style="padding-top:8px">
							
						</div>

					

				    
					</form>

				</div>

				
				<div class="bottom-promo"> 
				    
				</div>
				

                

				
				

					<h2>Comments and Discussions</h2>
					
					<p><img alt="Comment" src="./Custom Controls in Win32 API_ Standard Messages - CodeProject_files/NewComment.gif" width="12px" height="16px">
					<b>5 messages</b> have been posted for this article 
					Visit <b><a id="ctl00_ArticleLink" href="https://www.codeproject.com/Articles/624495/Custom-Controls-in-Win-API-Standard-Messages">https://www.codeproject.com/Articles/624495/Custom-Controls-in-Win-API-Standard-Messages</a></b> to post and view comments on 
					this article, or click <b><a id="ctl00_PrintWithMessage" href="https://www.codeproject.com/Articles/624495/Custom-Controls-in-Win-API-Standard-Messages?display=PrintAll">here</a></b> 
					to get a print view with messages.</p>
					
				

			</div>
			
		</td>
		<td width="170px" class="article-wing-right">
			
		</td>
		</tr></tbody></table>

		
		<div class="theme1-background" style="height:2px" id="stickyStop"></div>

		<div class="extended tiny-text">
			<div class="row">
				<div class="float-left">
					<a id="ctl00_PermaLink" href="https://www.codeproject.com/Articles/624495/Custom-Controls-in-Win-API-Standard-Messages">Permalink</a> | 
					<a id="ctl00_AdvertiseLink" href="http://developermedia.com/">Advertise </a> |
					<a id="ctl00_PrivacyLink" href="https://www.codeproject.com/info/privacy.aspx">Privacy</a> |
    				<a id="ctl00_CookiePolicyLink" href="https://www.codeproject.com/info/cookies.aspx">Cookies</a> |
                    <a id="ctl00_TermsOfUseLink" href="https://www.codeproject.com/info/TermsOfUse.aspx">Terms of Use</a> |
					<a id="ctl00_Mobile">Mobile</a>
					<br>
								
					
					Web06 |
					2.8.181119.1 |
					Last Updated 17 Mar 2014								
				</div>

                      

				<div class="float-right align-right">
					Article Copyright 2013 by Martin Mitáš<br>Everything else
					Copyright © <a href="mailto:webmaster@codeproject.com">CodeProject</a>, 1999-2018 <br>
				</div>

				

			</div>
		</div>
		

		<br clear="all">
		
			

	</div> 
	</div>
</div>






<script type="text/javascript" src="./Custom Controls in Win32 API_ Standard Messages - CodeProject_files/MemberProfilePopup.min.js.下载"></script>
<script type="text/javascript">//<![CDATA[
$(document).ready(function () {
   processCodeBlocks.Initialise('#contentdiv');
   thumbnailer.Initialise('#contentdiv',700,600);
});
cookieconsent.initialise({
                                enabled : true,
                                cookie  : { domain: 'codeproject.com' },
                                palette : {
                                    popup: { background: '#ff9900' },
                                    button: { background: '#f5d948' }
                                },
                                law :  {
                                    showForAllRegions : true, 
                                    countryCode : 'CN' 
                                },
                                theme: 'edgeless',
                                type : 'opt-in',
                                content: {
                                    message: 'Like every other website we use cookies. By using our site you acknowledge that you have read and understand our <a href=\'/info/cookie.aspx\'>Cookie Policy</a>, <a href=\'/info/privacy.aspx\'>Privacy Policy</a>, and our <a href=\'/info/TermsOfUse.aspx\'>Terms of Service</a>.',
                                    href:    'https://www.codeproject.com/info/privacy.aspx'
                                },
                                revokable:true,
                                onStatusChange: function(status) {
                                    $.ajax({
                                		dataType  : 'json',
                                        data: JSON.stringify({ allowCookies : this.hasConsented() }),
                                        url: '/script/Common/webservices/CommonServices.aspx/SetCookieConsent',
                                        cache: false,
                                        type: 'POST',
                                        contentType: 'application/json'
                                    })
                                    console.log(this.hasConsented() ? 'enable cookies' : 'disable cookies');
                                    console.log(this.hasAnswered() ? 'has answered' : 'did not answer');
                                },
                            });
$(document).ready(function() { anchorAnimate();
});
$(document).ready(function(){
    $('#__EVENTVALIDATION').attr('autocomplete', 'off');
});
$(function() {
                        var followServicectl00_AboutAuthorRptr_ctl00_AboutAuthor_FollowMember = new FollowService('/script/follow/webservices/followServices.aspx/', true);
                        followServicectl00_AboutAuthorRptr_ctl00_AboutAuthor_FollowMember.initFollowObjectButtons({
                            item : { 
                                objectTypeId   : 1,
                                objectId       : 5807385
                            },
                            followButtonId   : 'ctl00_AboutAuthorRptr_ctl00_AboutAuthor_FollowMember_FollowBtn',
                            unfollowButtonId : 'ctl00_AboutAuthorRptr_ctl00_AboutAuthor_FollowMember_UnfollowBtn'
                        }, false);
                    });

//]]>
</script>





<div id="MemberProfilePopupDiv" class="raised box" style="display: none; position: absolute;"></div><div id="MemberProfilePopupDiv" class="raised box" style="display: none; position: absolute;"></div><div id="MemberProfilePopupDiv" class="raised box" style="display: none; position: absolute;"></div></body></html>